/**********************************************************************************
Copyright (C), by AppleCai
Project                      : Study Kernel
Description                  : BSP level for cdev
History                      :
CPU and Compiler             : AM335x,ARM-LINIX-GCC
GenDate                      : 2020-10-13
OwnerBy                      : Apple Cai
**********************************************************************************/
#include <linux/module.h>  
#include <linux/init.h>  
#include <linux/types.h>  
#include <linux/fs.h>  
#include <linux/errno.h>  
#include <linux/mm.h>  
#include <linux/sched.h>  
#include <linux/cdev.h>  
#include <linux/slab.h>
#include <asm/io.h>  
#include <linux/version.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 3, 0)
        #include <asm/switch_to.h>
#else
        #include <asm/system.h>
#endif
#include <asm/uaccess.h>  
  
#define APPLEPAPER_SIZE 0x1000 /*全局内存最大4KB*/  
#define MEM_CLEAR 0x1 /*清零全局内存*/  
#define APPLEPAPERMAJOR 254  /* 预设的applepaper 的主设备号 */
  
static int applepaper_major = APPLEPAPERMAJOR;/*预设的applepaper的主设备号*/  
static struct class *apple_class;
  
/*applepaper的设备结构体：包含了对应于applepaper字符设备的cdev 和 使用内存mem[APPLEPAPER_SIZE]*/  
struct applepaper_dev  
{  
 struct cdev cdev;  //cdev结构体  
 unsigned char mem[APPLEPAPER_SIZE];  //全局内存  
};  
  
struct applepaper_dev *applepaper_devp;  //设备结构体指针  
  
/*文件打开函数*/  
int applepaper_open(struct inode *inode,struct file *filp)  
{  
 filp->private_data = applepaper_devp; //将设备结构体指针赋值给文件私有数据指针  
 return 0;  
}  
  
/*文件释放函数*/  
int applepaper_release(struct inode *inode,struct file *filp)  
{  
 return 0;  
}  


/*文件操作结构体*/  
static const struct file_operations applepaper_fops=  
{  
 .owner = THIS_MODULE,
 .open = applepaper_open,  
 .release = applepaper_release,
};  
  

  
/*设备驱动模块加载函数*/  
static int __init applepaper_init(void)  
{  
 int result;  
 struct device *apple_device;
 dev_t devno = MKDEV(applepaper_major,6);  
   
 //if(applepaper_major) //申请设备号  
 if (0)
 {  
 	printk("a\n");
  result = register_chrdev_region(devno,1,"applepaper");  
 }  
 else  //动态申请设备号  
 {  
 	printk("b\n");
  result = alloc_chrdev_region(&devno,6,1,"applepaper");  
  applepaper_major = MAJOR(devno);  

 }  
   
 if(result < 0)  
 {  
 	printk("1\n");
  return result;  
 }  
   
 applepaper_devp = kzalloc(sizeof(struct applepaper_dev),GFP_KERNEL); //申请设备结构体的内存  
 if(!applepaper_devp)  
 {  
  result = -ENOMEM;  
  goto fail_malloc;  
 }  
   printk("2\n");
 cdev_init(&applepaper_devp->cdev,&applepaper_fops);
  applepaper_devp->cdev.owner = THIS_MODULE;

  result = cdev_add(&applepaper_devp->cdev,devno,1);
  if(result<0)
  {
  	goto fail_malloc;
  }
 printk("3\n");
/* 在/sysfs文件夹下创建类*/
 apple_class = class_create(THIS_MODULE, "apple_class"); //创建my_class
 if(IS_ERR(apple_class))
 {
  printk("Err: failed in creating class.\n");
  return -1;
 }
 /* 创建设备节点文件 */
 apple_device = device_create( apple_class, NULL, MKDEV(applepaper_major, 6),NULL,"applepaper%d", 6 ); 
 if (IS_ERR(apple_device)) {
	result = PTR_ERR(apple_device);
    printk("err device_create");
    goto device_err;
 }
 else
 {
	printk (KERN_INFO "Registered character driver\n");
 }
 return 0;
   
fail_malloc:unregister_chrdev_region(devno,1); 
	return result; 
device_err:     
    class_destroy(apple_class); //É¾³ýÉè±¸Àà    
 	return result;  
}  
  
/*模块卸载函数*/  
void __exit applepaper_exit(void)  
{  
 cdev_del(&applepaper_devp->cdev); //注销cdev  
 kfree(applepaper_devp);          //释放设备结构体内存  
 device_destroy(apple_class, MKDEV(applepaper_major, 6));   // 删除设备节点
 class_destroy(apple_class);   // 删除设备类
 unregister_chrdev_region(MKDEV(applepaper_major,6),1); //释放设备号  
 printk("applepaper exit!\n");
}  
  
MODULE_AUTHOR("AppleCai");  
MODULE_LICENSE("GPL");  
 
module_init(applepaper_init);  
module_exit(applepaper_exit);   